package com.xiva.zk.curator;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.AuthInfo;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooDefs.Perms;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *  测试主类
 */
public class ZkCuratorDemoMain
{

    /**
     * 日志记录类
     */
    protected static Logger logger = LoggerFactory.getLogger(ZkCuratorDemoMain.class);


    private static CuratorFramework client;
    
    static
    {
        // 重试递增，最多重试3次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        List<AuthInfo> authInfos = new ArrayList<AuthInfo>();
        AuthInfo authInfo = new AuthInfo("digest", "admin:123".getBytes());

        authInfos.add(authInfo);
        
        client = CuratorFrameworkFactory.builder().connectString("192.168.88.128:2181,192.168.88.129:2181,192.168.88.130:2181")
                .authorization(authInfos).retryPolicy(retryPolicy).sessionTimeoutMs(3000).connectionTimeoutMs(3000).build();
    }
    
    
    private static void getData(String path) throws Exception
    {
        Stat stat = new Stat();
        
        byte[] res = client.getData().storingStatIn(stat).forPath(path);

//        System.out.println(new Date(stat.getCtime()));
        
        System.out.println(new String(res));
    }

    private static int getChildrenSize(String path) throws Exception
    {
        int childSize = client.getChildren().forPath(path).size();
        System.out.println(childSize);
        return  childSize;
    }
    
    /**
     * 
     * @param path
     * @throws Exception
     */
    public static void getDataWithACL(String path) throws Exception
    {
        // TODO 测试未通过
        ACL aclDigest = new ACL(Perms.READ | Perms.WRITE, new Id("digest", DigestAuthenticationProvider.generateDigest("admin:123")));
        List<ACL> aclList = new ArrayList<ACL>();
        aclList.add(aclDigest);
        
        Stat stat = new Stat();
        
//        client.setACL().withACL(pathAclList).forPath(path);
//        client.getZookeeperClient().getZooKeeper().addAuthInfo("digest", "admin:123".getBytes());
        
        byte[] res = client.getData().storingStatIn(stat).forPath(path);

//        System.out.println(stat.getCtime());
        
        System.out.println(new String(res));
    }

    /**
     * 写入数据
     * @param path
     * @param data
     * @throws Exception
     */
    public static void createData(String path, String data) throws Exception
    {
        Stat stat = client.checkExists().forPath(path);
        if (stat == null)
        {
            client.create().creatingParentsIfNeeded().forPath(path, data.getBytes());
        }
        else
        {
            logger.error("path :" + path + "is exist.");
        }

    }

    /**
     *
     * @param path
     * @param data
     * @throws Exception
     */
    public static void createDataWithACL(String path, String data) throws Exception
    {
        Stat stat = client.checkExists().forPath(path);
        System.out.println(stat);
        if (stat == null)
        {
            ACL aclIP = new ACL(Perms.READ, new Id("ip", "192.168.88.129"));
            ACL aclDigest = new ACL(Perms.READ | Perms.WRITE,
                    new Id("digest", DigestAuthenticationProvider.generateDigest("admin:123")));
            List<ACL> aclList = new ArrayList<ACL>();
            aclList.add(aclIP);
            aclList.add(aclDigest);
            
            client.create().withACL(aclList).forPath(path, data.getBytes());
        }
        else
        {
            logger.error("path :" + path + "is exist.");
        }
        
    }

    /**
     * 创建临时节点，服务断开时节点删除
     * @param servicePath
     * @param dataJson
     * @throws Exception
     */
    public static void createEphemeralNode(String servicePath, String dataJson) throws Exception
    {
        Stat stat = client.checkExists().forPath(servicePath);
        if (stat == null)
        {
            client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).forPath(servicePath, dataJson.getBytes());
        }
        else
        {
            logger.error("path :" + servicePath + "is exist.");
        }
    }

    public static void delNode(String path) throws Exception
    {
        client.delete().forPath(path);
    }

    public static void delChildNode(String path) throws Exception
    {
        client.delete().deletingChildrenIfNeeded().forPath(path);
    }
    
    public static void delNodeAsync(String path) throws Exception
    {
        client.delete().inBackground(new BackgroundCallback(){

            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception
            {
                Stat stat = event.getStat();
                System.out.println(stat);
            }
        }).forPath(path);
    }
    
    public static void getChildNode(String path) throws Exception
    {
        List<String> childPathList = client.getChildren().forPath(path);
        for (String childPath : childPathList)
        {
            System.out.println(childPath);
        }
    }
    
    public static void setNodeData(String path, String data) throws Exception
    {
        Stat stat = client.checkExists().forPath(path);
        System.out.println(stat);
        if (stat != null)
        {
            client.setData().forPath(path, data.getBytes());
        }
    }
    
    public static void addNodeListener()  throws Exception
    {
        // 注册节点监听器
        final NodeCache cache = new NodeCache(client, "/dubbo");
        cache.start();
        
        cache.getListenable().addListener(new NodeCacheListener(){
            
            public void nodeChanged() throws Exception
            {
                byte[] dataArray = cache.getCurrentData().getData();
                
                System.out.println(new String(dataArray));
            }
        });
    }
    
    public static void addChildListener() throws Exception
    {
        final PathChildrenCache childCache = new PathChildrenCache(client, "/dubbo", true);
        childCache.start();
        
        childCache.getListenable().addListener(new PathChildrenCacheListener(){

            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception
            {
                switch(event.getType())
                {
                    case CHILD_ADDED:
                        System.out.println("CHILD_ADDED:" + new String(event.getData().getData()));
                        break;
                    case CHILD_UPDATED:
                        System.out.println("CHILD_UPDATED:" + new String(event.getData().getData()));
                        break;
                    case CHILD_REMOVED:
                        System.out.println("CHILD_REMOVED:" + new String(event.getData().getData()));
                        break;
                    default:
                        break;
                }
            }
        });
    }

    static class CleanWorkThread extends Thread{

        private CuratorFramework client;

        public CleanWorkThread(CuratorFramework client)
        {
            this.client = client;
        }

        @Override
        public void run() {
            System.out.println("close client");
            client.close();
        }
    }
    
    public static void main(String[] args) throws Exception
    {
        Runtime.getRuntime().addShutdownHook(new CleanWorkThread(client));

        client.start();
        
//        addChildListener();
// web-video-stream-svr share-video-stream-srv  client-video-stream-srv
        String srvUrl = "ws://192.168.88.1:8554/channo/RealStream?type=CameraType&timestamp=1565792373265&weight=1000";
        String encodeUrl = URLEncoder.encode(srvUrl, "UTF-8");

        ServiceData srvData = new ServiceData();
        srvData.setIp("192.168.88.1");
        srvData.setPort("8554");
        srvData.setProtocolType("ws");

        String nodeData = JSONObject.toJSONString(srvData);
//        createData("/xsight/web-video-stream-svr/providers/" + encodeUrl, nodeData);

        createData("/xsight/web-video-stream-svr/routers", nodeData);
//        delNode("/xsight/web-video-stream-svr/providers/" + encodeUrl);

        System.in.read();
//        createData("/xsight/web-video-stream-svr/providers/" + encodeUrl, "192.168.88.1");

//        createData("/xsight/web-video-stream-svr/providers/" + encodeUrl + "/" + "channel_44030745555223344445_788886666", "192.168.88.45");
//        getChildrenSize("/xsight/web-video-stream-svr/providers/" + encodeUrl);

        //        createData("/xsight/web-video-stream-svr/consumers", "xinyi");
//
//        createData("/xsight/share-video-stream-srv/providers", "xinyi");
//        createData("/xsight/share-video-stream-srv/consumers", "xinyi");
//
//        createData("/xsight/client-video-stream-srv/providers", "xinyi");
//        createData("/xsight/client-video-stream-srv/consumers", "xinyi");

//        createData("/xsight/web-video-stream-svr/routers", "xinyi");
//        createData("/xsight/share-video-stream-srv/routers", "xinyi");
//        createData("/xsight/client-video-stream-srv/routers", "xinyi");
//        getData("/xsight/xvideo-srv");

//        delNode("/xsight/web-video-stream-svr/providers/" + encodeUrl + "/" + "channel_44030745555223344445_788886666" + encodeUrl);

/*        long startTime = System.currentTimeMillis();

        for(int i = 0; i< 100000; i++)
        {
            getData("/xsight/xvideo-srv");
        }

        long endTime = System.currentTimeMillis();

        System.out.println("cost time:" + (endTime - startTime));*/

//        createDataWithACL("/xsight/xvideo-srv-acl", "192.168.88.129:8080/userService");

//        getDataWithACL("/xsight/xvideo-srv-acl");

//        createData("/xsight/query-srv", "xinyi");

//        delNode("/dubbo/querySrv");
//        getChildNode("/dubbo");
        
    /*    setNodeData("/dubbo/querySrv", "person");
        setNodeData("/dubbo/querySrv1", "person2");*/
        
//        delNodeAsync("/dubbo/querySrv");

        //client.close();

//        Thread.sleep(Integer.MAX_VALUE);
        
    }


}
